package com.tianheng.wanzhou.datacollecting.util;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringEscapeUtils;
import org.slf4j.Logger;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.regex.Pattern;

@Slf4j
public class Data {

    private static Logger logger = null;
    public String value;
    public Data(){
        this.value = "";
    }

    public Data(Object value){
        if( value != null )
            this.value = value.toString();
    }

    public Data(String[] values){
        this.value = String.join(",", values);
    }

    public void clear() {
        this.value = "";
    }

    public JSON toJSON(boolean isArray){
        if( isArray )
            return JSON.parseArray(value);
        else
            return JSON.parseObject(value);
    }

    public long toLong(){
        return toLong(0L);
    }

    public long toLong(long df){
        if( this.value == null || this.value.equals("") || !isNumberString(this.value) )
            return df;

        return Long.parseLong(this.value);
    }

    public int toInt(){
        return this.toInt(0);
    }

    public float toFloat(){
        return this.toFloat(0.0f);
    }

    public double toDouble(){
        return this.toDouble(0.0);
    }

    public boolean toBool(){
        if( this.value == null || this.value.equals("") )
            return false;

        return Boolean.parseBoolean(this.value);
    }

    public boolean isEmpty(){
        if( this.value == null || this.value.equals("") || this.value.equals("0")
                || this.value.equalsIgnoreCase("undefined") )
            return true;

        if( !this.toBool() || this.toInt(0) == 0 )
            return true;

        return false;
    }

    public int toInt(int df){
        if( this.value == null || value.equals("") || !isNumberString(this.value) )
            return df;

        return Integer.parseInt(value);
    }

    public float toFloat(float df){
        if( this.value == null || value.equals("") || !isNumberString(this.value) )
            return df;

        return Float.parseFloat(value);
    }

    public double toDouble(double df){
        if( this.value == null || value.equals("") || !isNumberString(this.value) )
            return df;

        return Double.parseDouble(value);
    }

    public String toString(String df){
        if( this.value == null || this.value.equals("") )
            return df;

        return this.value;
    }

    public static boolean isEmpty(String item){
        return item == null || item.equalsIgnoreCase("");
    }

    public static boolean isNumberString(String item){
        if( isEmpty(item) )
            return false;

        String regex = "^\\d+(\\.\\d+)?$";

        return Pattern.matches(regex, item);
    }

    public String toString(){
        return this.toString("");
    }

    public static Object bind(Object bean, Map<String, Data> params){
        Class cn = null;
        try {
            cn = Class.forName(bean.getClass().getName());
        } catch (ClassNotFoundException e) {
            return bean;
        }

        if( cn == null )
            return bean;

        Field[] fields = bean.getClass().getDeclaredFields();
        int length = fields.length;
        if( length < 1 )
            return bean;
//        Method[] methods =cn.getMethods();

        for(Field field : fields) {
            field.setAccessible(true);

            String name = field.getName();

            if (!params.containsKey(name))
                continue;

            String type = field.getGenericType().toString();


            PropertyDescriptor pd = null;
            try {
                pd = new PropertyDescriptor(name, cn);
            } catch (IntrospectionException e) {
                e.printStackTrace();
            }
            Method method = pd.getWriteMethod();
            try {
                switch (type) {
                    case "int":
                    case "class java.lang.Integer":
                        if (method != null)
                            method.invoke(bean, params.get(name).toInt());
                        else
                            field.set(bean, params.get(name).toInt());
                        break;
                    case "boolean":
                    case "class java.lang.Boolean":
                        if (method != null)
                            method.invoke(bean, params.get(name).toBool());
                        else
                            field.set(bean, params.get(name).toBool());
                        break;
                    case "long":
                    case "class java.lang.Long":
                        if (method != null)
                            method.invoke(bean, params.get(name).toLong());
                        else
                            field.set(bean, params.get(name).toLong());
                        break;
                    case "float":
                    case "class java.lang.Float":
                        if (method != null)
                            method.invoke(bean, params.get(name).toFloat());
                        else
                            field.set(bean, params.get(name).toFloat());
                        break;
                    case "double":
                    case "class java.lang.Double":
                        if (method != null)
                            method.invoke(bean, params.get(name).toDouble());
                        else
                            field.set(bean, params.get(name).toDouble());
                        break;
                    case "class java.lang.String":
                    default:
                        String content = params.get(name).toString();
                        if( content.contains("<") || content.contains(">") )
                            content = StringEscapeUtils.escapeHtml(content);

                        if (method != null)
                            method.invoke(bean,content );
                        else
                            field.set(bean, content);
                        break;
                }
            }catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) {
                log.error(name + " bind Failed");
            }
        }

        return bean;
    }
}
